package com.ossjk.payment.util;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.ossjk.core.util.CommonUtil;
import com.ossjk.payment.bo.Condition;
import com.ossjk.payment.bo.Expression;
import com.ossjk.payment.bo.Formula;

public class PaymentUtil {

	private static Logger logger = LoggerFactory.getLogger(PaymentUtil.class);

	// 薪酬组成
	private List<Expression> expressions;
	// 薪酬
	private Formula formula;
	// 薪酬组成表达式
	private String expressionsJson;
	// 薪酬表达式
	private String formulaJson;
	// 薪酬赋值后表达式
	private String finalFormula;
	// 变量map
	private Map<String, String> varMap;
	// 系统常量薪酬
	private Map<String, String> sysMap;
	// 常量薪酬
	private List<Expression> conExpressions = new ArrayList();
	// 变量薪酬
	private List<Expression> varExpressions = new ArrayList();
	// 系统常量薪酬
	private List<Expression> sysExpressions = new ArrayList();

	/**
	 * 转换薪酬组成对象
	 */
	private void convertExpressions() {
		expressions = JSON.parseArray(expressionsJson, Expression.class);
	}

	/**
	 * 返回薪酬表达式
	 */
	public String getFormulaJson() {
		convertFormulaJson();
		return formulaJson;
	}

	/**
	 * 返回薪酬组成表达式
	 */
	public String getExpressionsJson() {
		convertExpressionsJson();
		return expressionsJson;
	}

	/**
	 * 返回薪酬赋值后表达式
	 */
	public String getFinalFormula() {
		return finalFormula;
	}

	/**
	 * 转换薪酬组成表达式
	 */
	public void convertExpressionsJson() {
		expressionsJson = JSON.toJSONString(expressions);
	}

	/**
	 * 转换薪酬表达式
	 */
	private void convertFormulaJson() {
		formulaJson = JSON.toJSONString(formula);
	}

	/**
	 * 薪酬组成归类
	 * 
	 * @throws Exception
	 */
	private void classifyExpressions() throws Exception {
		if (!CommonUtil.isBlank(expressions)) {
			String value = null;
			for (Expression expression : expressions) {
				if (CommonUtil.isEquals(expression.getType(), "1")) {
					conExpressions.add(expression);
				} else if (CommonUtil.isEquals(expression.getType(), "2")) {
					varExpressions.add(expression);
				} else if (CommonUtil.isEquals(expression.getType(), "3")) {
					sysExpressions.add(expression);
				}
			}
		} else {
			throw new Exception("薪酬组成表达式为空。");
		}
	}

	/**
	 * 薪酬组成注入
	 * 
	 * @throws Exception
	 */
	private void fillExpressions() throws Exception {
		if (!CommonUtil.isBlank(expressions)) {
			String value = null;
			for (Expression expression : expressions) {
				if (CommonUtil.isEquals(expression.getType(), "2")) {
					value = varMap.get(expression.getKey());
					if (CommonUtil.isBlank(value)) {
						throw new Exception("变量属性" + expression.getKey() + "注入失败。");
					}
					expression.setValue(value);
				} else if (CommonUtil.isEquals(expression.getType(), "3")) {
					value = sysMap.get(expression.getKey());
					if (CommonUtil.isBlank(value)) {
						throw new Exception("系统常量属性" + expression.getKey() + "注入失败。");
					}
					expression.setValue(value);
				}
			}
		} else {
			throw new Exception("薪酬组成表达式为空。");
		}
	}

	public double handlePayment(String expressionsJson, String formulaJson, Map<String, String> varMap, Map<String, String> sysMap) throws Exception {
		this.expressionsJson = expressionsJson;
		this.formulaJson = formulaJson;
		this.varMap = varMap;
		this.sysMap = sysMap;
		// 转换薪酬组成对象
		convertExpressions();
		// 薪酬组成注入
		fillExpressions();
		// 薪酬组成归类
		classifyExpressions();
		// 薪酬表达式常量替换
		formulaJson = replaceFormula(formulaJson, conExpressions, 1);
		// 薪酬表达式变量替换
		formulaJson = replaceFormula(formulaJson, varExpressions, 2);
		// 薪酬表达式系统常量替换
		formulaJson = replaceFormula(formulaJson, sysExpressions, 3);
		// 开始处理条件
		formula = JSON.parseObject(formulaJson, Formula.class);
		// 计算公式
		List<Condition> conditions = formula.getConditions();
		boolean flag = true;
		double count = 0;
		if (!CommonUtil.isBlank(conditions)) {
			for (Condition condition : conditions) {
				if (judgeJs(condition.getCondition())) {
					flag = false;
					finalFormula = condition.getFormula();
					count = calculateJs(condition.getFormula()).doubleValue();
					break;
				}
			}
		}
		if (flag) {
			count = calculateJs(formula.getDefaultformula()).doubleValue();
		}
		return count;
	}

	public double handlePayment(String expressionsJson, String formulaJson) throws Exception {
		this.expressionsJson = expressionsJson;
		this.formulaJson = formulaJson;
		// 转换薪酬组成对象
		convertExpressions();
		// 薪酬组成归类
		classifyExpressions();
		// 薪酬表达式常量替换
		formulaJson = replaceFormula(formulaJson, conExpressions, 1);
		// 薪酬表达式变量替换
		formulaJson = replaceFormula(formulaJson, varExpressions, 2);
		// 薪酬表达式系统常量替换
		formulaJson = replaceFormula(formulaJson, sysExpressions, 3);
		// 开始处理条件
		formula = JSON.parseObject(formulaJson, Formula.class);
		// 计算公式
		List<Condition> conditions = formula.getConditions();
		boolean flag = true;
		double count = 0;
		if (!CommonUtil.isBlank(conditions)) {
			for (Condition condition : conditions) {
				if (judgeJs(condition.getCondition())) {
					flag = false;
					finalFormula = condition.getFormula();
					count = calculateJs(condition.getFormula()).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
					break;
				}
			}
		}
		if (flag) {
			count = calculateJs(formula.getDefaultformula()).doubleValue();
		}

		return count;
	}

	private BigDecimal calculateJs(String js) throws Exception {
		ScriptEngine jse = new ScriptEngineManager().getEngineByName("JavaScript");
		return new BigDecimal(jse.eval("(" + js + ").toFixed(2)") + "");
	}

	private boolean judgeJs(String js) throws Exception {
		ScriptEngine jse = new ScriptEngineManager().getEngineByName("JavaScript");
		return (boolean) jse.eval(js);
	}

	private String replaceFormula(String formulaJson, List<Expression> expressions, Integer type) {
		if (!CommonUtil.isBlank(expressions)) {
			for (Expression expression : expressions) {
				String key = expression.getKey();
				if (type == 2) {
					key = "#" + key;
				}
				if (type == 3) {
					key = "\\$" + key;
				}
				formulaJson = formulaJson.replaceAll(key, expression.getValue());
			}
		}
		return formulaJson;
	}

//	public static void main(String[] args) throws ScriptException {
//		// ScriptEngine jse = new ScriptEngineManager().getEngineByName("JavaScript");
//		// System.out.println(jse.eval("200+255"));
//
//		String expressionsJson = "[\r\n" + "  {\r\n" + "    \"type\": \"1\",\r\n" + "    \"name\": \"基本工资\",\r\n" + "    \"key\": \"jbgz\",\r\n" + "    \"value\": \"2500\"\r\n" + "  },\r\n" + "  {\r\n" + "    \"type\": \"1\",\r\n" + "    \"name\": \"生活报销\",\r\n" + "    \"key\": \"shbx\",\r\n" + "    \"value\": \"2500\"\r\n" + "  },\r\n" + "  {\r\n" + "    \"type\": \"1\",\r\n" + "    \"name\": \"每天课酬\",\r\n" + "    \"key\": \"mtkc\",\r\n" + "    \"value\": \"110\"\r\n" + "  },\r\n" + "  {\r\n" + "    \"type\": \"1\",\r\n" + "    \"name\": \"晚修课酬\",\r\n" + "    \"key\": \"wxkc\",\r\n" + "    \"value\": \"60\"\r\n" + "  },\r\n" + "  {\r\n" + "    \"type\": \"2\",\r\n" + "    \"name\": \"绩效\",\r\n" + "    \"key\": \"jx\"\r\n" + "  },\r\n" + "  {\r\n" + "    \"type\": \"2\",\r\n" + "    \"name\": \"晚修天数\",\r\n" + "    \"key\": \"wxts\"\r\n" + "  },\r\n" + "  {\r\n" + "    \"type\": \"2\",\r\n" + "    \"name\": \"考勤扣减\",\r\n" + "    \"key\": \"kqkj\"\r\n" + "  },\r\n" + "  {\r\n"
//				+ "    \"type\": \"2\",\r\n" + "    \"name\": \"其他\",\r\n" + "    \"key\": \"qt\"\r\n" + "  },\r\n" + "  {\r\n" + "    \"type\": \"3\",\r\n" + "    \"name\": \"个人所得税\",\r\n" + "    \"key\": \"grsdsl\"\r\n" + "  }\r\n" + "]";
//
//		String formulaJson = "{\r\n" + "  \"conditions\": [\r\n" + "    {\r\n" + "      \"condition\": \"jbgz>5000\",\r\n" + "      \"formula\": \"jbgz+wxkc*#jx*$grsdsl\"\r\n" + "    }\r\n" + "  ],\r\n" + "  \"default\": \"jbgz+wxkc*#jx\"\r\n" + "}";
//		Map<String, String> varMap = new HashMap<String, String>();
//		varMap.put("jx", "22");
//		varMap.put("wxts", "4");
//		varMap.put("kqkj", "20");
//		varMap.put("qt", "0");
//		Map<String, String> sysMap = new HashMap<String, String>();
//		sysMap.put("grsdsl", "0.38");
//		PaymentUtil paymentUtil = new PaymentUtil();
//		try {
//			paymentUtil.handlePayment(expressionsJson, formulaJson, varMap, sysMap);
//			paymentUtil.handlePayment(expressionsJson, formulaJson);
//		} catch (Exception e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}
//
//	}
}
